import requests
import hashlib
import hmac
import time
import uuid
import re
import xml.etree.ElementTree as ET
from typing import Dict, List, Optional, Any, Union
from .base_client import CloudClient

# 天翼云盘API配置
TV_APP_KEY = "600100885"
TV_APP_SIGNATURE_SECRET = "fe5734c74c2f96a38157f420b32dc995"
TV_VERSION = "6.5.5"
ANDROID_TV = "FAMILY_TV"
TV_CHANNEL_ID = "home02"
API_URL = "https://api.cloud.189.cn"

class Cloud189Client(CloudClient):
    """天翼网盘客户端实现"""
    
    def __init__(self):
        super().__init__()
        self.session = requests.Session()
        self.temp_uuid = None
        self.family_id = None
        
    def client_suffix(self):
        """客户端参数"""
        return {
            "clientType": ANDROID_TV,
            "version": TV_VERSION,
            "channelId": TV_CHANNEL_ID,
            "clientSn": "unknown",
            "model": "PJX110",
            "osFamily": "Android",
            "osVersion": "35",
            "networkAccessMode": "WIFI",
            "telecomsOperator": "46011"
        }
    
    def get_http_date_str(self):
        """获取HTTP规范时间"""
        return time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime())
    
    def timestamp(self):
        """获取时间戳(毫秒)"""
        return int(time.time() * 1000)
    
    def session_key_signature_of_hmac(self, session_secret, session_key, operate, full_url, date_of_gmt):
        """SessionKey HMAC签名"""
        url_path = re.search(r'://[^/]+((/[^/\s?#]+)*)', full_url).group(1)
        data = f"SessionKey={session_key}&Operate={operate}&RequestURI={url_path}&Date={date_of_gmt}"
        signature = hmac.new(session_secret.encode(), data.encode(), hashlib.sha1).hexdigest().upper()
        return signature
    
    def app_key_signature_of_hmac(self, session_secret, app_key, operate, full_url, timestamp):
        """AppKey HMAC签名"""
        url_path = re.search(r'://[^/]+((/[^/\s?#]+)*)', full_url).group(1)
        data = f"AppKey={app_key}&Operate={operate}&RequestURI={url_path}&Timestamp={timestamp}"
        signature = hmac.new(session_secret.encode(), data.encode(), hashlib.sha1).hexdigest().upper()
        return signature
    
    def signature_header(self, url, method, is_family=False):
        """生成签名头"""
        date_of_gmt = self.get_http_date_str()
        session_key = self.token_info.get('sessionKey', '')
        session_secret = self.token_info.get('sessionSecret', '')
        
        if is_family:
            session_key = self.token_info.get('familySessionKey', '')
            session_secret = self.token_info.get('familySessionSecret', '')
        
        return {
            "Date": date_of_gmt,
            "SessionKey": session_key,
            "X-Request-ID": str(uuid.uuid4()),
            "Signature": self.session_key_signature_of_hmac(session_secret, session_key, method, url, date_of_gmt)
        }
    
    def app_key_signature_header(self, url, method):
        """生成AppKey签名头"""
        temp_time = self.timestamp()
        return {
            "Timestamp": str(temp_time),
            "X-Request-ID": str(uuid.uuid4()),
            "AppKey": TV_APP_KEY,
            "AppSignature": self.app_key_signature_of_hmac(TV_APP_SIGNATURE_SECRET, TV_APP_KEY, method, url, temp_time)
        }
    
    def get_qr_uuid(self) -> Optional[str]:
        """获取二维码UUID"""
        url = f"{API_URL}/family/manage/getQrCodeUUID.action"
        headers = self.app_key_signature_header(url, "GET")
        params = self.client_suffix()
        
        response = self.session.get(url, headers=headers, params=params)
        print(f"QR UUID Response Status: {response.status_code}")
        print(f"QR UUID Response Text: {response.text}")
        
        if response.status_code == 200:
            try:
                # 尝试解析XML
                root = ET.fromstring(response.text)
                uuid_element = root.find('uuid')
                if uuid_element is not None:
                    return uuid_element.text
            except Exception as e:
                print(f"XML parse error: {e}")
                # 如果XML解析失败，尝试JSON
                try:
                    data = response.json()
                    if 'uuid' in data:
                        return data['uuid']
                except Exception as json_e:
                    print(f"JSON decode error: {json_e}")
                return None
        return None
    
    def check_qr_login(self, uuid: str) -> Optional[str]:
        """检查二维码登录状态"""
        url = f"{API_URL}/family/manage/qrcodeLoginResult.action"
        headers = self.app_key_signature_header(url, "GET")
        params = self.client_suffix()
        params['uuid'] = uuid
        
        response = self.session.get(url, headers=headers, params=params)
        print(f"Check Login Response Status: {response.status_code}")
        print(f"Check Login Response Text: {response.text}")
        
        if response.status_code == 200:
            try:
                # 尝试解析JSON
                data = response.json()
                if 'accessToken' in data:
                    return data['accessToken']
            except Exception as e:
                print(f"JSON decode error: {e}")
                # 如果JSON解析失败，尝试XML
                try:
                    root = ET.fromstring(response.text)
                    # 查找e189AccessToken元素
                    access_token_element = root.find('e189AccessToken')
                    if access_token_element is not None:
                        return access_token_element.text
                    # 如果没找到，尝试查找accessToken
                    access_token_element = root.find('accessToken')
                    if access_token_element is not None:
                        return access_token_element.text
                except Exception as xml_e:
                    print(f"XML parse error: {xml_e}")
                return None
        return None
    
    def login_with_token(self, access_token: str) -> bool:
        """使用AccessToken登录"""
        url = f"{API_URL}/family/manage/loginFamilyMerge.action"
        headers = self.app_key_signature_header(url, "GET")
        params = self.client_suffix()
        params['e189AccessToken'] = access_token
        
        response = self.session.get(url, headers=headers, params=params)
        print(f"Login Merge Response Status: {response.status_code}")
        print(f"Login Merge Response Text: {response.text}")
        
        if response.status_code == 200:
            try:
                data = response.json()
                if 'sessionKey' in data:
                    self.token_info = data
                    return True
            except Exception as e:
                print(f"JSON decode error: {e}")
                # 如果JSON解析失败，尝试XML
                try:
                    root = ET.fromstring(response.text)
                    # 解析XML中的各个字段
                    login_name = root.find('loginName')
                    session_key = root.find('sessionKey')
                    session_secret = root.find('sessionSecret')
                    family_session_key = root.find('familySessionKey')
                    family_session_secret = root.find('familySessionSecret')
                    
                    if session_key is not None:
                        self.token_info = {
                            'loginName': login_name.text if login_name is not None else '',
                            'sessionKey': session_key.text,
                            'sessionSecret': session_secret.text if session_secret is not None else '',
                            'familySessionKey': family_session_key.text if family_session_key is not None else '',
                            'familySessionSecret': family_session_secret.text if family_session_secret is not None else ''
                        }
                        return True
                except Exception as xml_e:
                    print(f"XML parse error: {xml_e}")
                return False
        return False
    
    def get_file_list(self, folder_id: str = "-11", is_family: bool = False) -> Optional[Dict[str, Any]]:
        """获取文件列表"""
        if not self.token_info:
            return None
            
        url = f"{API_URL}/family/file/listFiles.action" if is_family else f"{API_URL}/listFiles.action"
        headers = self.signature_header(url, "GET", is_family)
        params = self.client_suffix()
        params['folderId'] = folder_id
        params['recursive'] = '0'
        params['orderBy'] = 'filename'
        params['order'] = 'ASC'
        
        response = self.session.get(url, headers=headers, params=params)
        print(f"File List Response Status: {response.status_code}")
        print(f"File List Response Text: {response.text}")
        
        if response.status_code == 200:
            try:
                root = ET.fromstring(response.text)
                
                # 解析文件列表XML结构
                file_list = []
                folder_list = []
                print(f"开始解析")
        
                # 查找fileList节点
                file_list_node = root.find('fileList')
                if file_list_node is not None:
                    # 解析文件夹
                    for folder in file_list_node.findall('folder'):
                        folder_info = {
                            'id': folder.find('id').text if folder.find('id') is not None else '',
                            'parentId': folder.find('parentId').text if folder.find('parentId') is not None else '',
                            'name': folder.find('name').text if folder.find('name') is not None else '',
                            'createDate': folder.find('createDate').text if folder.find('createDate') is not None else '',
                            'lastOpTime': folder.find('lastOpTime').text if folder.find('lastOpTime') is not None else '',
                            'fileCount': folder.find('fileCount').text if folder.find('fileCount') is not None else '0',
                            'isFolder': True
                        }
                        folder_list.append(folder_info)
                    
                    # 解析文件
                    for file in file_list_node.findall('file'):
                        file_info = {
                            'id': file.find('id').text if file.find('id') is not None else '',
                            'parentId': file.find('parentId').text if file.find('parentId') is not None else '',
                            'name': file.find('name').text if file.find('name') is not None else '',
                            'size': file.find('size').text if file.find('size') is not None else '0',
                            'createDate': file.find('createDate').text if file.find('createDate') is not None else '',
                            'lastOpTime': file.find('lastOpTime').text if file.find('lastOpTime') is not None else '',
                            'isFolder': False
                        }
                        file_list.append(file_info)
                print(f"解析结果1: {file_list}")
                print(f"解析结果2: {folder_list}")
                return {
                    'fileList': file_list,
                    'folderList': folder_list,
                    'lastRev': root.find('lastRev').text if root.find('lastRev') is not None else ''
                }
                
            except Exception as xml_e:
                print(f"XML parse error: {xml_e}")
                return None
    
    def get_file_info(self, file_id: str, is_family: bool = False) -> Optional[Dict[str, Any]]:
        """获取文件详细信息"""
        if not self.token_info:
            return None
            
        # 通过获取文件列表来查找特定文件的详细信息
        # 首先需要获取文件的父目录ID
        url = f"{API_URL}/family/file/listFiles.action" if is_family else f"{API_URL}/listFiles.action"
        headers = self.signature_header(url, "GET", is_family)
        params = self.client_suffix()
        params['folderId'] = '-11'  # 从根目录开始搜索
        params['recursive'] = '1'   # 递归搜索
        params['orderBy'] = 'filename'
        params['order'] = 'ASC'
        
        response = self.session.get(url, headers=headers, params=params)
        
        if response.status_code == 200:
            try:
                root = ET.fromstring(response.text)
                file_list_node = root.find('fileList')
                
                if file_list_node is not None:
                    # 搜索指定ID的文件
                    for file in file_list_node.findall('file'):
                        if file.find('id') is not None and file.find('id').text == file_id:
                            # 解析文件的详细信息
                            file_info = {
                                'id': file.find('id').text if file.find('id') is not None else '',
                                'parentId': file.find('parentId').text if file.find('parentId') is not None else '',
                                'name': file.find('name').text if file.find('name') is not None else '',
                                'size': int(file.find('size').text) if file.find('size') is not None else 0,
                                'md5': file.find('md5').text if file.find('md5') is not None else '',
                                'createDate': file.find('createDate').text if file.find('createDate') is not None else '',
                                'lastOpTime': file.find('lastOpTime').text if file.find('lastOpTime') is not None else '',
                                'rev': file.find('rev').text if file.find('rev') is not None else '',
                                'mediaType': file.find('mediaType').text if file.find('mediaType') is not None else '',
                                'isFolder': False,
                                'path': self._get_file_path(file.find('parentId').text if file.find('parentId') is not None else '', is_family)
                            }
                            
                            # 尝试获取图标信息
                            icon_node = file.find('icon')
                            if icon_node is not None:
                                file_info['icon'] = {
                                    'smallUrl': icon_node.find('smallUrl').text if icon_node.find('smallUrl') is not None else '',
                                    'largeUrl': icon_node.find('largeUrl').text if icon_node.find('largeUrl') is not None else ''
                                }
                            
                            return file_info
                            
                return None
                
            except Exception as e:
                print(f"获取文件信息失败: {e}")
                return None
        
        return None
    
    def _get_file_path(self, parent_id: str, is_family: bool = False) -> str:
        """获取文件路径（简化实现）"""
        if parent_id == '-11' or parent_id == '':
            return '/'
        # 这里可以实现更复杂的路径获取逻辑
        return f'/folder_{parent_id}/'
    
    def create_upload_session(self, parent_id: str, file_md5: str, file_name: str, 
                            file_size: int, is_family: bool = False) -> Optional[Dict[str, Any]]:
        """创建上传会话"""
        if not self.token_info:
            return None
            
        url = f"{API_URL}/family/file/createFamilyFile.action" if is_family else f"{API_URL}/createUploadFile.action"
        headers = self.signature_header(url, "POST", is_family)
        
        if is_family:
            # 家庭云使用查询参数
            params = {
                'familyId': self.family_id,
                'parentId': parent_id,
                'fileMd5': file_md5,
                'fileName': file_name,
                'fileSize': file_size,
                'resumePolicy': '1'
            }
            params.update(self.client_suffix())
            response = self.session.post(url, headers=headers, params=params)
        else:
            # 个人云使用表单数据
            data = {
                'parentFolderId': parent_id,
                'fileName': file_name,
                'size': file_size,
                'md5': file_md5,
                'opertype': '3',
                'flag': '1',
                'resumePolicy': '1',
                'isLog': '0'
            }
            data.update(self.client_suffix())
            response = self.session.post(url, headers=headers, data=data)
        
        print(f"Create Upload Session Response Status: {response.status_code}")
        print(f"Create Upload Session Response Text: {response.text}")
        
        if response.status_code == 200:
            try:
                # 尝试解析XML
                root = ET.fromstring(response.text)
                
                # 解析XML响应
                result = {}
                for child in root:
                    if child.tag == 'uploadFileId':
                        result['uploadFileId'] = child.text
                    elif child.tag == 'fileUploadUrl':
                        result['fileUploadUrl'] = child.text
                    elif child.tag == 'fileCommitUrl':
                        result['fileCommitUrl'] = child.text
                    elif child.tag == 'fileDataExists':
                        result['fileDataExists'] = int(child.text)
                
                print(f"XML parsed result: {result}")
                return result
            except Exception as xml_e:
                print(f"XML decode error: {xml_e}")
                return None
    
    def upload_file_data(self, upload_info: Dict[str, Any], file_content: bytes, 
                        is_family: bool = False) -> bool:
        """上传文件数据"""
        upload_url = upload_info.get('fileUploadUrl')
        if not upload_url:
            return False
            
        files = {
            'file': ('file', file_content, 'application/octet-stream')
        }
        
        response = self.session.post(upload_url, files=files)
        print(f"Upload File Data Response Status: {response.status_code}")
        print(f"Upload File Data Response Text: {response.text}")
        
        return response.status_code == 200
    
    def commit_upload(self, commit_url: str, upload_file_id: str, is_family: bool = False, 
                     is_rapid: bool = False, overwrite: bool = False) -> Optional[Dict[str, Any]]:
        """提交上传"""
        if not commit_url:
            return None
            
        headers = self.signature_header(commit_url, "POST", is_family)
        
        if is_family:
            # 家庭云使用请求头
            headers.update({
                'ResumePolicy': '1',
                'UploadFileId': str(upload_file_id),
                'FamilyId': str(self.family_id)
            })
            response = self.session.post(commit_url, headers=headers)
        else:
            # 个人云使用表单数据
            data = {
                'opertype': '3' if overwrite else '1',
                'resumePolicy': '1',
                'uploadFileId': str(upload_file_id),
                'isLog': '0'
            }
            data.update(self.client_suffix())
            response = self.session.post(commit_url, headers=headers, data=data)
        
        print(f"Commit Upload Response Status: {response.status_code}")
        print(f"Commit Upload Response Text: {response.text}")
        
        if response.status_code == 200:
            try:
                # 尝试解析XML
                root = ET.fromstring(response.text)
                
                # 解析XML响应
                result = {}
                for child in root:
                    result[child.tag] = child.text
                
                print(f"XML parsed result: {result}")
                return result
            except Exception as xml_e:
                print(f"XML decode error: {xml_e}")
                return None
    
    def get_download_url(self, file_id: str, is_family: bool = False) -> Optional[str]:
        """获取下载链接"""
        if not self.token_info:
            return None
            
        url = f"{API_URL}/family/file/getFileDownloadUrl.action" if is_family else f"{API_URL}/getFileDownloadUrl.action"
        headers = self.signature_header(url, "GET", is_family)
        params = self.client_suffix()
        params['fileId'] = file_id
        
        # 个人云模式需要额外参数
        if not is_family:
            params.update({
                'dt': '3',
                'flag': '1'
            })
        
        response = self.session.get(url, headers=headers, params=params)
        print(f"Get Download URL Response Status: {response.status_code}")
        print(f"Get Download URL Response Text: {response.text}")
        
        if response.status_code == 200:
            try:
                # 尝试解析XML
                root = ET.fromstring(response.text)
                
                # 直接获取XML根元素的文本内容作为下载URL
                download_url = root.text if root.text else None
                print(f"XML parsed download URL: {download_url}")
            except Exception as xml_e:
                print(f"XML decode error: {xml_e}")
                return None
            
            if download_url:
                # 处理URL格式
                download_url = download_url.replace('&amp;', '&').replace('http://', 'https://')
                
                # 处理重定向获取真实下载链接
                try:
                    redirect_response = self.session.get(download_url, allow_redirects=False)
                    if redirect_response.status_code == 302:
                        real_download_url = redirect_response.headers.get('location')
                        if real_download_url:
                            download_url = real_download_url
                            print(f"Got redirected download URL: {download_url}")
                except Exception as redirect_e:
                    print(f"Redirect handling error: {redirect_e}")
                
                return download_url
        return None
    
    @property
    def is_logged_in(self) -> bool:
        """检查是否已登录"""
        return self.token_info is not None and 'sessionKey' in self.token_info
    
    def get_client_name(self) -> str:
        """获取客户端名称"""
        return "天翼网盘"